home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Development Platforms / Apple II / Essentials / Technical.Notes / IIGS / TN.IIGS.054 < prev    next >
Encoding:
Text File  |  1991-01-11  |  39.7 KB  |  1,097 lines  |  [TEXT/pdos]

  1. Apple II
  2. Technical Notes
  3. _____________________________________________________________________________
  4.                                                   Developer Technical Support
  5.  
  6.  
  7. Apple IIgs
  8. #54:    MIDI Drivers
  9.  
  10. Revised by:    Matt Deatherage                                  November 1990
  11. Written by:    Jim Mensch                                            May 1989
  12.  
  13. This Technical Note describes how to write a driver for use with the Apple IIgs
  14. MIDI tools.
  15. Changes since May 1989:  Noted that MIDI drivers also work with the MIDI Synth
  16. tool.
  17. _____________________________________________________________________________
  18.  
  19. Apple ships two drivers with the MIDI tool set, APPLE.MIDI and CARD6850.MIDI,
  20. respectively.  These drivers are adequate for almost all MIDI hardware
  21. currently on the market for the Apple IIgs; however, if your hardware is not
  22. compatible with either of these drivers, you have to write your own.  This Note
  23. includes all the information you need to create a MIDI driver. Note that the
  24. same drivers that work with MIDI Tools (Tool #32) also work with the MIDI Synth
  25. (Tool #35).  This Note collectively refers to MIDI Tools and MIDI Synth as the
  26. "MIDI tools."
  27.  
  28.  
  29. Purpose of the Driver and Description of Hardware Requirements
  30.  
  31. The Apple MIDI tools communicate to the MIDI world via a simple driver.  The
  32. driver's function is managing the transmission and reception of single bytes of
  33. MIDI data between the tools and the particular MIDI hardware involved.  The
  34. MIDI tools operate on the assumption that the hardware has a method of
  35. interrupting the system when a character has been received and when a character
  36. can be transmitted.  Since there is quite a bit of overhead in processing MIDI
  37. data, and since MIDI data can comes across a standard MIDI bus at a rate of
  38. over 3000 bytes per second, it is suggested that you provide a means for your
  39. device to buffer a few characters to reduce system overhead caused by
  40. interrupts if you are designing hardware to be used with the MIDI tools.
  41.  
  42.  
  43. Format of the Driver File
  44.  
  45. The driver file is a standard OMF load file, which can be created with any of
  46. the popular Apple IIgs assemblers.  The file must start with a dispatch table
  47. that contains the addresses of the standard driver routines.  All driver
  48. routines must be in the same segment as the dispatch table.  The dispatch table
  49. should have 13 four-byte entries, each of which contains the address of the
  50. appropriate routine minus one.  Table 1 contains addresses of routines in the
  51. MIDI driver to perform specific functions.
  52.  
  53.  
  54.               Call          Function
  55.               ______________________________________________________
  56.               Init          Called to initialize the port and prime
  57.                             the driver
  58.               ShutDown      Called to close the port and clean up
  59.                             after driver
  60.               Reset         Called at reset time by the MIDI tools
  61.               IntHandler    Called when your interrupt occurs
  62.               PollRecv      Poll input the port for data
  63.               RecvIntOn     Turns on receiver interrupts
  64.               RecvIntOff    Turns off receiver interrupts
  65.               PollXmit      Polls the transmitter to see if another
  66.                             character can be sent
  67.               XmitIntOn     Enables transmitter interrupts
  68.               XmitIntOff    Disables transmitter interrupts
  69.               NotImp        Currently unused
  70.               NotImp        Currently unused
  71.               NotImp        Currently unused
  72.               _____________________________________________________
  73.  
  74.                     Table 1-MIDI Driver Function Routines
  75.  
  76.  
  77. Routine Calling Conventions
  78.  
  79. All driver routines are called with full 16-bit mode enabled and should exit
  80. the same way.  On entry to each routine, the accumulator contains the direct
  81. page pointer that the driver should use if it wants to use the MIDI Tools' or
  82. MIDI Synth's direct page.  It is the driver's responsibility to set the direct
  83. page register and restore it on exit.  All other parameters are passed on the
  84. stack and should be removed from the stack before the routine exits.  The MIDI
  85. tools set aside 128 bytes of space on the passed direct page for use by the
  86. driver.  They are bytes $80-$FF.
  87.  
  88. If you want to report an error inside of any routine (except IntHandler), set
  89. the carry flag on exit and load the accumulator with the error code.  Use
  90. predefined error codes whenever possible.  If you need to report a device
  91. specific error, use errors in the range $C0-$FF.  The MIDI tools will set the
  92. high byte of the error code properly for you, so you do not need to do it
  93. yourself.  Table 2 lists all of the potential predefined error codes.
  94.  
  95.       Error Code              Error Definition
  96.       _____________________________________________________________
  97.       miToolsErr ($2004)        The required tools were not started
  98.       miNoBufErr ($2007)        No buffer is currently allocated
  99.       miDevNotAvail ($2080)     Requested device is not available
  100.       miDevSlotBusy ($2081)     Requested slot is already in use
  101.       miDevBusy ($2082)         Requested device is already in use
  102.       miDevOverrun ($2083)      Device overrun by incoming MIDI
  103.                                 data
  104.       miDevNoConnect ($2084)    No connection to MIDI
  105.       miDevReadErr ($2085)      Framing error in received MIDI data
  106.       miDevVersion ($2086)      ROM version is incompatible with
  107.                                 driver
  108.       miDevIntHndlr ($2087)     Conflicting interrupt handler
  109.                                 installed
  110.       _____________________________________________________________
  111.  
  112.                     Table 2-Predefined Eror Codes
  113.  
  114.  
  115. The Driver Routines
  116.  
  117. Init
  118.  
  119. This routine is called by the MIDI tools when it wants to initialize your port
  120. and tell the driver to prepare itself for the rest of the calls.  Figure 1
  121. shows how the stack looks on entry to this call.
  122.  
  123.  
  124.  
  125.  
  126.                     Figure 1-The Stack on Entry to Init
  127.  
  128. The Init routine should first test to see if the port specified by SlotFlag and
  129. SlotNum is available for use.  SlotNum is the number of the slot or the port
  130. that the user has requested for use, and SlotFlag indicates whether it is a
  131. built-in port or a card in a slot.  After determining that the requested device
  132. is available, you should initialize the device, allocate any memory that your
  133. driver may require (beyond what is available in the direct page), and set the
  134. proper system interrupt vector to the address passed in NewIntAddr.  Before
  135. setting the vector, be sure to save the old value, as the MIDI tools expect the
  136. result from this routine to be the old address stored in the vector.  On exit,
  137. the stack should contain the return address and the old vector address.
  138.  
  139. ShutDown
  140.  
  141. This routine is called when the MIDI tools want your driver to release the MIDI
  142. device and prepare to be unloaded.  Figure 2 shows how the stack looks on entry
  143. to this call.
  144.  
  145.  
  146.  
  147.  
  148.                     Figure 2-The Stack on Entry to ShutDown
  149.  
  150. Your routine should change the interrupt vector that you used to OldIntVector.
  151. It should then deallocate all the memory that it allocated, disable all
  152. interrupts on the device, and if needed, tell the system that you are no longer
  153. using the port in question.
  154.  
  155. Reset
  156.  
  157. This routine is called when the system has been reset by the user.  Figure 3
  158. shows how the stack looks on entry to this call.
  159.  
  160.  
  161.  
  162.  
  163.                     Figure 3-The Stack on Entry to Reset
  164.  
  165. All you should do at this point is attempt to deallocate any memory you were
  166. using and disable interrupts on the device you were using.
  167.  
  168. Note:    Do not set the interrupt vector to OldIntVector, instead
  169.          remove the value from the stack and dispose of it.
  170.  
  171. IntHandler
  172.  
  173. The IntHandler routine is called by the MIDI tools when an interrupt occurs for
  174. the vector that you are using.  The MIDI driver performs some setup then calls
  175. your routine.  This routine does not have any parameters on the stack.
  176.  
  177. Once called, your IntHandler routine should test the port to see if an
  178. interrupt has occurred on your device.  If your device did not cause the
  179. interrupt, you should set the carry and exit as quickly as possible, reducing
  180. the system interrupt overhead.
  181.  
  182. If your device caused the interrupt, you should test the receiver to see if any
  183. bytes of data are waiting to be read.  If there is data waiting, you should
  184. load that data into the accumulator and perform a JSL to the following code:
  185.  
  186.         InBufGlue    PEA $0400
  187.                      PHD
  188.                      RTL
  189.  
  190. This code calls the MIDI tools and tell them to accept the character in the
  191. accumulator into its input buffer.  After accepting the data, control is passed
  192. back to the instruction following your JSL.  If you received a byte of data and
  193. an error occurred during reception, you should load the number of the error
  194. code into the y register and perform a JSL to the following code:
  195.  
  196.         InErrGlue    PEA $0500
  197.                      PHD
  198.                      RTL
  199.  
  200. Again, you will regain control right after the JSL.  Once in your interrupt
  201. routine, you may perform the calls above for as much data as you like.  For
  202. example, if your device has a three-byte buffer, you could call InBufGlue once
  203. for each waiting character, thus reducing your interrupt overhead and possibly
  204. preventing unneeded interrupts.
  205.  
  206.  
  207. If the transmitter on your device is ready to send data, you should perform a
  208. JSL to the following code:
  209.  
  210.         OutBufGlue    PEA $8400
  211.                       PHD
  212.                       RTL
  213.  
  214. This routine will return with the carry set if no data is waiting to be
  215. transmitted or the carry clear if data is available.  If data is waiting, the
  216. next character to send will be in the accumulator, and you should simply send
  217. it at that time.  If no more data is available, you should disable transmitter
  218. interrupts and exit.  The MIDI tools will re-enable transmitter interrupts the
  219. next time it has data to send.
  220.  
  221. PollRecv
  222.  
  223. The PollRecv (Poll Receive) routine is called by the MIDI tools every now and
  224. then to see if any data might be waiting to be read.  There are no parameters
  225. on the stack for this call.  Your driver should test to see if any data is
  226. available and transmit it all to the MIDI tools via the InBufGlue described in
  227. the IntHandler description.
  228.  
  229. PollXmit
  230.  
  231. The PollXmit (Poll Transmit) routine is called by the MIDI tools when any data
  232. is added to the MIDI output buffer.  There are no parameters on the stack for
  233. this routine.  Your driver should enable transmitter interrupts, test to see if
  234. it can send any data immediately, and if it can, call OutBufGlue as described
  235. int the IntHandler description to get data to send.
  236.  
  237. XmitIntOn and RecvIntOn
  238.  
  239. These routines are called when the MIDI tools want to explicitly enable
  240. transmitter or receiver interrupts. They have no parameters on the stack and
  241. should, when called, enable transmitter interrupts for XmitIntOn and receiver
  242. interrupts for RecvIntOn.
  243.  
  244.  
  245. XmitIntOff and RecvIntOff
  246.  
  247. These routine are called when the MIDI tools want to explicitly disable
  248. transmitter or receiver interrupts.  They have no parameters on the stack and
  249. should, when called, disable transmitter interrupts for XmitIntOff and receiver
  250. interrupts for RecvIntOff.
  251.  
  252. NotImp
  253.  
  254. These routines are not yet implemented, but your driver should be ready to
  255. handle a call to them.  When called, they should clear the accumulator, clear
  256. the carry and perform an RTL back to the MIDI tools.
  257.  
  258.  
  259.  
  260. A MIDI Driver Skeleton
  261.  
  262. You can use the following sample code as a basis for a MIDI driver.  It is not
  263. a complete driver in itself, and you will need to add code where comments with
  264. asterisks (***) appear for it to be functional.  This example is in MPW IIgs
  265. assembler format.
  266.  
  267.  
  268. ******************************************************************************
  269. * MIDI.DRVR.Aii
  270. *
  271. * (C)  Copyright Apple Computer, Inc. 1988
  272. * All rights reserved.
  273. *
  274. * by Don Marsh & Jim Mensch
  275. * 10/26/88
  276. *
  277. * This is a shell that can be used to create custom MIDI drivers for use with
  278. * the Apple MIDI tool set. This shell is not functional, but can be used as a
  279. * starting point for creating your own custom MIDI drivers.
  280. *
  281. * Files:    System Macros and equates
  282. *
  283. *
  284. *
  285. * Modification History:
  286. *
  287. * Version 1.0   Mensch
  288. *
  289. *      10/26/88
  290. *
  291. *      Create first     draft
  292. *
  293. ******************************************************************************
  294.         Include 'E16.MIDI'
  295.         Include 'M16.MiscTool'
  296.         Include 'E16.MiscTool'
  297.         Include 'M16.util'
  298.  
  299. ;
  300. ; Direct page usage     Note:
  301. ; MIDI drivers may use the upper half ($80-$FF) of the MIDI direct page. When
  302. ; a MIDI driver routine is called the Accumulator will contain the direct page
  303. ; pointer for the MIDI tool set. If your driver requires more storage than
  304. ; 128 bytes, it will have to allocate them itself using the memory manager.
  305.  
  306. theuserID       equ $80         ; location to store the passed user ID
  307. PortInUse       equ theuserID+2 ; storage for the port number in use
  308. deref           equ PortInUse+2
  309. Temp            equ Deref+4
  310.                 EJECT
  311.  
  312. ************************************************************
  313. *******************
  314. *
  315. DispatchTable   RECORD
  316. *
  317. * Description:  Every MIDI Driver must start with a driver dispatch table
  318. *       that contains the entry point minus 1 of each of the
  319. *       required entry points.
  320. *
  321. *
  322. * Inputs:       None
  323. *
  324. * Outputs:      None
  325. *
  326. * External Refs:
  327.                 Import DRVRInit
  328.                 Import DRVRShutDown
  329.                 Import DRVRReset
  330.                 Import DRVRIntHandler
  331.                 Import DRVRPollRecv
  332.                 Import DRVRRecvIntOn
  333.                 Import DRVRRecvIntOff
  334.                 Import DRVRPollXmit
  335.                 Import DRVRXmitIntOn
  336.                 Import DRVRXmitIntOff
  337.                 Import DRVRNotImplemented
  338. *
  339. * Entry Points: None
  340. *
  341. ************************************************************
  342. *******************
  343.  
  344.                 DC.L DRVRInit
  345.                 DC.L DRVRShutDown
  346.                 DC.L DRVRReset
  347.                 DC.L DRVRIntHandler
  348.                 DC.L DRVRPollRecv
  349.                 DC.L DRVRRecvIntOn
  350.                 DC.L DRVRRecvIntOff
  351.                 DC.L DRVRPollXmit
  352.                 DC.L DRVRXmitIntOn
  353.                 DC.L DRVRXmitIntOff
  354.                 DC.L DRVRNotImplemented
  355.                 DC.L DRVRNotImplemented
  356.                 DC.L DRVRNotImplemented
  357.  
  358.  
  359. ; a few of the routines will need a temporary storage location that can be used
  360. ; even after the direct page is set back to what it was, This is a good place
  361. ; to put it!
  362.  
  363. ErrorCode       ds.W 1                  ; temporary holder of an error code
  364.                 EndR
  365.  
  366.                 EJECT
  367.  
  368. ************************************************************
  369. *******************
  370. *
  371. DRVRInit        PROC
  372. *
  373. * Description:  This is called by the MIDI Tools when it needs to Init
  374. *       your MIDI Driver. This is usually in response to a MIDIxxx
  375. *       call made by the application.
  376. *       When this routine is called, you should allocate any buffer
  377. *       space that you will need beyond the direct page, you should
  378. *       enable the interrupts on your MIDI Device, and then set the
  379. *       appropriate system interrupt vector and return the old vector
  380. *       value. If the init works fine, clear the carry and return.
  381. *       If an error occurs return the appropriate error code
  382. *       in the Accumulator, and set the carry.
  383. *
  384. *
  385. * Inputs:       UserID:Word             ID of application, for mem allocation
  386. *               SlotFlag:Word           0 for internal port/ 1 for slot
  387. *               SlotNum:Word            number of slot/port to use
  388. *               NewIntVector:Long       address to give system as its new
  389. *                                       interrupt vector. This routine is in
  390. the
  391. *                                       MIDI tool set, and it performs needed
  392. *                                       setup before it calls your interrupt
  393. *                                       routine
  394. *
  395. * Outputs:      OldIntVector:Long       Address interrupt vector used to have
  396. *
  397. * External Refs:        None
  398. *
  399. * Entry Points: None
  400. *
  401. ************************************************************
  402. *******************
  403. ; Offsets for parameters on the stack
  404.  
  405. ProcStatus      equ 1
  406. OldDPage        equ ProcStatus+1
  407. ReturnAddress   equ OldDPage+2
  408. UserID          equ ReturnAddress+3
  409. SlotFlag        equ UserID+2
  410. SlotNum equ SlotFlag+2
  411. NewIntVector    equ SlotNum+2
  412. OldIntVector    equ NewIntVector+4
  413. ParmBytes       equ 10
  414. ParmEnd equ ReturnAddress+ParmBytes
  415.  
  416. ; first disable interrupts since we are going to be setting up interrupt
  417. vectors
  418. ; and enabling interrupt generating hardware. We wouldn't want an interrupt to
  419. go
  420. ; off before we were ready to handle it! Then set us up to use the MIDI direct
  421. ; page.
  422.  
  423.                 php                     ; save the old proc status
  424.                 phd                     ; save the old direct page
  425.                 tcd                     ; Set Direct page to the one passed
  426.                 SEI                     ; and disable interrupts
  427.  
  428. ; now get the user ID and save it, and allocate any buffers that we may need
  429. ; Since most drivers will never need more than 128 bytes of storage we will
  430. ; not allocate any storage space
  431.  
  432.                 lda UserID,s            ; first save the user ID for later
  433.                 sta theUserID           ; in our section of the MIDI DPage
  434.  
  435. ; *** Insert any memory allocation needed here ***
  436.  
  437. ; Next, you should check the slot flag and number to see if they are compatible
  438. ; with this driver. If they are, you should continue and initialize the proper
  439. ; port. If they are not proper, you should exit with an error.
  440. ; For this example, I will be testing the SlotFlag, to see if it is set to
  441. ; external.
  442.  
  443.                 lda SlotFlag,s  ; first test the slot flag to be sure
  444.                 bne FlagOK              ; its non-zero.
  445.  
  446.                 ldy #miDevNotAvail      ; if its zero, signal not available
  447.                 bra InitError           ; and exit via error routine
  448.  
  449. FlagOK          lda SlotNum,s           ; Now save the slot number in
  450.                 sta PortInUse           ; our data area
  451.  
  452. ; *** At this point you should test the firmware in the desired slot to be sure
  453. ; that the card you want is properly installed, if it is not then you should
  454. ; pass back the appropriate error ***
  455.  
  456. ; Now that you know that you have the proper slot information and you have
  457. tested
  458. ; to be sure that you have the hardware needed for the driver it is time for
  459. you
  460. ; to initialize the interface and to enable its interrupts.
  461.  
  462. ; *** Install code to initialize your hardware/interrupts here ***
  463.  
  464. ; Now that the Port has been properly initialized, you must set up the proper
  465. ; system interrupt vector. Since we required an external card above it would
  466. ; make sense that you need to use the "Other unspecified interrupt handler"
  467. ; vector (Number $0017). But first, remember to get the original vector pointer
  468. ; because we must return it to the MIDI tools.
  469.  
  470.                 PushLong #0             ; space for result
  471.                 PushWord #otherIntHnd ; vector to retrieve
  472.                 _GetVector              ; and get the vector in question
  473.                 PullLong Temp           ; place in storage for a sec
  474.  
  475.                 lda Temp                ; now place it on the stack
  476.                 sta OldIntVector        ; as the result of this function
  477.                 lda Temp+2
  478.                 sta OldIntVector+2
  479.  
  480.                 lda NewIntVector        ; now move the MIDI Interrupt routine
  481.                 sta Temp                ; pointer into temporary storage
  482.                 lda NewIntVector+2
  483.                 sta Temp+2
  484.  
  485.                 PushWord #otherIntHnd ; now set the vector to point to
  486.                 PushLong Temp           ; the MIDI drivers interrupt routine
  487.                 _SetVector
  488.  
  489. ; The driver is now all set up, pull off the passed parms and we are done!
  490. Done            ldy #0                  ; set the error code to 0. No error
  491. ;
  492. ; This is the alternate label for the Done routine that should be called when
  493. ; an error has occurred.
  494. InitError
  495.                 lda ReturnAddress,s     ; Move the return address below the
  496.                 sta ParmEnd,s           ; parameters
  497.                 lda ReturnAddress+1,s
  498.                 sta ParmEnd+1,s
  499.  
  500.                 pld                     ; get the direct page back
  501.                 plp                     ; get the processor status back
  502.  
  503.                 tsc                     ; now adjust the stack pointer
  504.                 sec                     ; so that the parameters are gone
  505.                 sbc #ParmBytes
  506.                 tcs                     ; now the return address is on Top
  507.  
  508.                 tya                     ; put any error into <A>
  509.                 cmp #1                  ; set the carry if non-zero
  510.                 RTL                     ; and return
  511.  
  512.                 EndP
  513.  
  514.                 EJECT
  515. ************************************************************
  516. *******************
  517. *
  518. DRVRShutDown    PROC
  519. *
  520. * Description:  This routine will be called whenever the MIDI Tools want
  521. *       to cause your driver to let go of the port it was using.
  522. *
  523. *
  524. * Inputs:       OldIntVector:Long       Address to place back into the system
  525. *                                       interrupt vector you were using
  526. *
  527. * Outputs:      Carry clear if successful
  528. *               Carry set if not, error in <A>
  529. *
  530. * External Refs:
  531.         Import DrvrRecvIntOff
  532.         Import DRVRXMitIntOff
  533. *
  534. * Entry Points:
  535. *
  536. ************************************************************
  537. *******************
  538.                 With DispatchTable
  539.  
  540. ProcStatus      equ 1
  541. OldDPage        equ ProcStatus+1
  542. ReturnAddress   equ OldDPage+2
  543. OldIntVector    equ ReturnAddress+3
  544. ParmBytes       equ 4
  545. ParmEnd equ ReturnAddress+ParmBytes
  546.  
  547. ; first disable interrupts since we are going to be setting up interrupt
  548. vectors
  549. ;  We wouldn't want an interrupt to go off before we were ready to handle it!
  550. ; Then set us up to use the MIDI direct page.
  551.  
  552.                 php                     ; save the old proc status
  553.                 phd                     ; save the old direct page
  554.                 tcd                     ; Set Direct page to the one passed
  555.                 SEI                     ; and disable interrupts
  556.  
  557.                 lda #0                  ; zero out the temp error code
  558.                 sta >ErrorCode
  559. ; Now First, re-install the old interrupt vector
  560.  
  561.                 lda OldIntVector        ; get the old vector off the stack
  562.                 sta Temp                ; and save it in globals for a sec
  563.                 lda OldIntVector+2
  564.                 sta Temp+2
  565.  
  566.                 PushWord #otherIntHnd ; now set the vector to point to
  567.                 PushLong Temp           ; its original routine.
  568.                 _SetVector
  569.  
  570. ; Next, turn off the interface hardware, and tell it to stop generating
  571. ; interrupts. We can share some code here and call our DRVRRecvIntOff and
  572. ; DRVRXmitIntOff routines. Always remember load the direct page into the
  573. ; accumulator.
  574.  
  575.                 tdc                     ; get direct page into <A>
  576.                 jsl DRVRXmitIntOff      ; and turn off transmitter interrupts
  577.  
  578.                 tdc
  579.                 jsl DRVRRecvIntOff      ; and now receiver interrupts.
  580.  
  581. ; *** Usually turning off interrupts will be all that you would need to do at
  582. ; this point, however, if your interface card requires extra shutdown code
  583. ; this is where you would place it ***
  584.  
  585. ; *** If you allocated any memory in the DRVRInit call, this is the place to
  586. ; get rid of it.
  587.  
  588. ; If an error were to occur in this routine, you should simply store the error
  589. ; number in our temporary error code variable like this
  590. ;
  591. ;               lda #ErrorNumber
  592. ;               Sta >ErrorCode
  593.  
  594.  
  595. Done
  596. ; Now that we are done shutting down the driver, pull off the passed data
  597. ; and end.
  598.                 pld                     ; first retrieve the old dpage
  599.                 plp                     ; and processor status
  600.  
  601.                 Longa Off               ; next move the return address
  602.                 SEP #$20                ; we need a short acc for this trick
  603.  
  604.                 pla                     ; pull the 3 byte return address
  605.                 ply                     ; into <A> and <Y>
  606.  
  607.                 plx                     ; now remove the remaining bytes
  608.                 plx                     ; of passed parameters
  609.  
  610.                 phy                     ; and restore the return address
  611.                 pha
  612.  
  613.                 Longa On
  614.                 REP #$30                ; and turn back on full 16-bit mode
  615.  
  616.                 lda >ErrorCode  ; retrieve the error code
  617.                 cmp #1                  ; and set the carry if non-zero
  618.                 RTL
  619.                 EndP
  620.  
  621.                 EJECT
  622.  
  623. ************************************************************
  624. *******************
  625. *
  626. DRVRReset       PROC
  627. *
  628. * Description:  This routine will be called whenever MIDIReset is called.
  629. *       and that should only happen when an actual reset occurred.
  630. *       It should in most cases perform the exact same functions
  631. *       as MIDI Shutdown.
  632. *
  633. *
  634. * Inputs:       OldIntVector:Long       Original contents of interrupt vector
  635. *
  636. * Outputs:      None
  637. *
  638. * External Refs:
  639. *
  640. * Entry Points:
  641. *
  642. ************************************************************
  643. *******************
  644.  
  645.         jmp DRVRShutDown
  646.  
  647.         EndP
  648.  
  649.         EJECT
  650. ************************************************************
  651. *******************
  652. *
  653. DRVRIntHandler  PROC
  654. *
  655. * Description:  This routine is the very core of the MIDI driver. It takes
  656. *       care of passing data back and forth between the MIDI tools
  657. *       and your hardware. It will be called for both input and
  658. *       output.
  659. *
  660. *
  661. * Inputs:       None
  662. *
  663. * Outputs:      Carry set if interrupt not serviced
  664. *
  665. * External Refs:
  666.                 Import DRVRXmitIntOff
  667. *
  668. * Entry Points:
  669.                 Export InBufGlue
  670.                 Export InErrGlue
  671.                 Export OutBufGlue
  672. *
  673. ************************************************************
  674. *******************
  675.  
  676.                 phd                     ; first, save the current dpage
  677.                 tcd                     ; and use the MIDI DPage
  678.  
  679. ; The first thing the interrupt routine should do is to test to see if the
  680. ; interrupt was actually generated by our port. If it was then we should handle
  681. ; it, but if not, we should simply exit this routine with the carry set as
  682. ; fast as we can, so that the next interrupt handler will get it in a timely
  683. ; manner.
  684.  
  685. ; *** Insert code here to test to see if the original interrupt was yours ***
  686.  
  687.                 beq ServicePort ; if it was our, handle it
  688.  
  689. ; If the interrupt was not ours, set the carry and leave
  690.                 pld                     ; restore the direct page
  691.                 sec
  692.                 rtl
  693.  
  694. ServicePort                             ; the interrupt was ours, continue
  695.  
  696. ; This routine should test the interrupt again, too see if the port is ready
  697. ; to transmit or receive, If it is ready to transmit or receive, it should
  698. ; then call the ServiceRecv, or ServiceXMit routines
  699.  
  700. ; *** Insert code here to test for receive
  701.  
  702.                 bne ServiceRecv ; if chars waiting try receive it
  703.  
  704. ; If no more characters are waiting, see if we are ready to transmit any
  705. ; characters.
  706.  
  707.                 bne ServiceXMit ; if can send a character do it
  708.  
  709. ; If both the above tests fail, then exit the interrupt handler for now
  710.                 pld                     ; restore the direct page
  711.                 clc                     ; clear the carry to indicate serviced
  712.                 RTL                     ; and return
  713.  
  714. ; The following routine ServiceRecv will be called when a character is waiting
  715. ; It should retrieve that character, pass it to the MIDI drivers, and then
  716. ; branch back to the beginning of ServicePort, to see if any more chars are
  717. ; waiting.
  718. ServiceRecv
  719.  
  720. ; *** Place code here that retrieves a byte of data from the port ***
  721.  
  722. ; Call MIDI tools this way if no error has occurred on receive (<A> contains
  723. the
  724. ; data read)
  725. RecvOK
  726.                 jsl InBufGlue           ; call the MIDI tools
  727.                 bra ServicePort ; and check for more data in or out
  728.  
  729. ; Call MIDI this way if a reception error has occurred (<A> contains the
  730. ; data read)
  731. RecvErr
  732.                 ldy #miDevReadErr       ; load Y with the error
  733.                 jsl InErrGlue           ; call the midi tools
  734.                 bra ServicePort
  735.  
  736. ; The routine ServiceXmit will be called when the port is ready to send data.
  737. ; it will actually call the MIDI tools and get a character to send.
  738. ServiceXmit
  739.  
  740.                 jsl OutBufGlue  ; call the MIDI tools for the next char
  741.                 bcs NoMoreData  ; if the carry set then no data to send
  742.  
  743. ; *** at this point the byte to transmit is in <A>, place your code to output
  744. ; it thru the port here ***
  745.  
  746.  
  747. ; Now that the data has been sent, you can either loop thru ServicePort again,
  748. ; or you could simply end and wait for the next interrupt to send another
  749. ; character. This sample will simply exit at this point
  750.         bra Done        ; after sending the character end.
  751.  
  752. ; NoMoreData is called when the MIDI Tools said that they did not have any more
  753. ; data to transmit, so we should turn off transmitter interrupts at this point
  754. ; in case our device likes to keep interrupting if its empty.
  755. NoMoreData
  756.                 phd                     ; push the direct page reg on the stack
  757.                 jsl DRVRXmitIntOff      ; enable xmit interrupts
  758. Done
  759.                 pld                     ; restore the DPage
  760.                 clc                     ; signal the interrupt as handled
  761.                 rtl                     ; and get outta here!
  762.  
  763. ; The routine inbufglue should be called when you received a character from
  764. your
  765. ; port with no error and you want to pass it to the MIDI tools.
  766. InBufGlue       pea $0400               ; push on the long address of the
  767.                 phd                     ; direct page and a proc status byte
  768.                 RTL                     ; and jump back to the MIDI tools
  769.  
  770. ; The routine inErrGlue should be called when you received a character from
  771. your
  772. ; port and an error has occurred. In this case, it should still be passed to
  773. the
  774. ; MIDI driver, as it may still be useful
  775. inErrGlue       pea $0500               ; push on the long address of the
  776.                 phd                     ; direct page and a proc status byte
  777.                 RTL                     ; and jump back to the MIDI tools
  778.  
  779. ; The routine OutBufGlue should be called when you are ready to send a char
  780. ; out your port. The MIDI tools will will return with the character to send
  781. ; in <A>. If the MIDI tools have no more characters to send then OutBufGlue
  782. ; will return with the carry set.
  783. OutBufGlue      pea $8400               ; push on the long address of the
  784.                 phd                     ; direct page and a proc status byte
  785.                 RTL                     ; and jump back to the MIDI tools
  786.                 EndP
  787.  
  788.                 EJECT
  789. ************************************************************
  790. *******************
  791. *
  792. DRVRPollRecv    PROC
  793. *
  794. * Description:  This routine is called by the MIDI tools when it wants to
  795. *       pool the port for data instead of waiting for an interrupt.
  796. *       its function is similar to that of the our interrupt handler
  797. *       except that it only does input.
  798. *
  799. * Inputs:       None
  800. *
  801. * Outputs:      Carry set if interrupt not serviced
  802. *
  803. * External Refs:
  804.                 Import InBufGlue
  805.                 Import InErrGlue
  806. *
  807. * Entry Points: None
  808. *
  809. ************************************************************
  810. *******************
  811.  
  812.                 phd                     ; first, save the current dpage
  813.                 tcd                     ; and use the MIDI DPage
  814.                 php
  815.                 SEI
  816.  
  817. ServicePort                             ; the interrupt was ours, continue
  818.  
  819. ; This routine should test the port too see if the port has any data for use
  820. ; to receive. If it does, it calls the MIDI tools and hands it off. Also note
  821. ; this routine will turn off interrupts, since we wouldn't want any stray
  822. ; receiver interrupts to spoil our fun and grab the data from us. (This is
  823. ; very important for certain types of ports which may signal that the port
  824. ; is ready and the generate an interrupt, thus leaving us in a situation where
  825. ; our interrupt routines could steal the interrupt right out from under us
  826. before
  827. ; we fetched it, thus allowing us to possibly double post a character.
  828.  
  829. ; *** Insert code here to test for received data ***
  830.  
  831.                 bne ServiceRecv ; if chars waiting try receive it
  832.  
  833.  
  834. ; If no more data is waiting  exit this routine.
  835.                 plp
  836.                 pld                     ; restore the direct page
  837.                 clc                     ; clear the carry no errors possible
  838.                 RTL                     ; and return
  839.  
  840. ; The following routine ServiceRecv will be called when a character is waiting
  841. ; It should retrieve that character, pass it to the MIDI drivers, and then
  842. ; branch back to the beginning of ServicePort, to see if any more chars are
  843. ; waiting.
  844. ServiceRecv
  845.  
  846. ; *** Place code here that retrieves a byte of data from the port ***
  847.  
  848. ; Call MIDI tools this way if no error has occurred on receive (<A> contains
  849. the
  850. ; data read)
  851. RecvOK
  852.                 jsl InBufGlue           ; call the MIDI tools
  853.                 bra ServicePort ; and check for more data in or out
  854.  
  855. ; Call MIDI this way if a reception error has occurred (<A> contains the
  856. ; data read)
  857. RecvErr
  858.                 ldy #miDevReadErr       ; load Y with the error
  859.                 jsl InErrGlue           ; call the midi tools
  860.                 bra ServicePort
  861.                 EndP
  862.                 EJECT
  863.  
  864. ************************************************************
  865. *******************
  866. *
  867. DRVRPollXMit    PROC
  868. *
  869. * Description:  This routine is called when the MIDI tools wants to start
  870. *                       an output stream. The tool set calls this routine for
  871. the
  872. *                       first character of data, and then this routine is
  873. *                       responsible for enabling transmitter interrupts and
  874. sending
  875. *                       the character.
  876. *
  877. *
  878. * Inputs:       None
  879. *
  880. * Outputs:      Carry set if interrupt not serviced
  881. *
  882. * External Refs:        None
  883.                 Import OutBufGlue
  884.                 Import DRVRXmitIntOn
  885. *
  886. * Entry Points: None
  887. *
  888. ************************************************************
  889. *******************
  890.  
  891.                 phd                     ; first, save the current dpage
  892.                 tcd                     ; and use the MIDI DPage
  893.                 php                     ; disable interrupts as we are now
  894. going
  895.                 SEI                     ; to turn on xmitter interrupts.
  896.  
  897. ; First see if the port is ready to send any data, if not simply exit
  898.  
  899. ; *** Insert code here to test if output is ready ***
  900.  
  901.                 bcs Done                ; if not, then simply end
  902.  
  903. ; The port is ready to accept a character for output so, call MIDI tools
  904. ; to get the next character
  905.  
  906.                 jsl OutBufGlue  ; get the next character
  907.                 bcs Done                ; if carry set, no chars to xmit so end
  908.  
  909.  
  910.                 pha                     ; save the character to send
  911.                 phd                     ; push the direct page reg on the stack
  912.                 jsl DRVRXmitIntOn       ; enable xmit interrupts
  913.                 pla                     ; retrieve the character to send
  914.  
  915. ; *** Insert code here to transmit a character ***
  916. Done
  917.                 plp                     ; get the old interrupt status
  918.                 pld                     ; get the old direct page
  919.                 lda #0                  ; no errors are possible
  920.                 clc
  921.                 rtl
  922.  
  923.                 EndP
  924.  
  925.                 EJECT
  926.  
  927. ************************************************************
  928. *******************
  929. *
  930. DRVRXmitIntOn   PROC
  931. *
  932. * Description:  This routine will be called when the MIDI tools need to
  933. *       enable transmitter interrupts on your device.
  934. *
  935. *
  936. * Inputs:       None
  937. *
  938. * Outputs:      None
  939. *
  940. * External Refs:
  941. *
  942. * Entry Points:
  943. *
  944. ************************************************************
  945. *******************
  946.  
  947.                 php                     ; save proc status/interrupt state
  948.                 phd                     ; save the old direct page
  949.                 tcd                     ; use the MIDI tools DPage
  950.                 SEI                     ; disable interrupts
  951.  
  952. ; *** Insert code here to enable transmitter interrupts on your device
  953.  
  954.                 pld                     ; recover old direct page
  955.                 plp                     ; recover old interrupt state
  956.                 lda #0                  ; and return no-error (none possible)
  957.                 clc
  958.                 rtl
  959.                 EndP
  960.  
  961. ************************************************************
  962. *******************
  963. *
  964. DRVRXmitIntOff  PROC
  965. *
  966. * Description:  This routine will be called when the MIDI tools need to
  967. *                       Disable transmitter interrupts on your device.
  968. *
  969. *
  970. * Inputs:       None
  971. *
  972. * Outputs:      None
  973. *
  974. * External Refs:
  975. *
  976. * Entry Points:
  977. *
  978. ************************************************************
  979. *******************
  980.  
  981.                 php                     ; save proc status/interrupt state
  982.                 phd                     ; save the old direct page
  983.                 tcd                     ; use the MIDI tools DPage
  984.                 SEI                     ; disable interrupts
  985.  
  986. ; *** Insert code here to Disable transmitter interrupts on your device
  987.  
  988.                 pld                     ; recover old direct page
  989.                 plp                     ; recover old interrupt state
  990.                 lda #0                  ; and return no-error (none possible)
  991.                 clc
  992.                 rtl
  993.                 EndP
  994.  
  995.                 EJECT
  996.  
  997. ************************************************************
  998. *******************
  999. *
  1000. DRVRRecvIntOn   PROC
  1001. *
  1002. * Description:  This routine will be called when the MIDI tools need to
  1003. *       enable receiver interrupts on your device.
  1004. *
  1005. *
  1006. * Inputs:       None
  1007. *
  1008. * Outputs:      None
  1009. *
  1010. * External Refs:
  1011. *
  1012. * Entry Points:
  1013. *
  1014. ************************************************************
  1015. *******************
  1016.  
  1017.                 php                     ; save proc status/interrupt state
  1018.                 phd                     ; save the old direct page
  1019.                 tcd                     ; use the MIDI tools DPage
  1020.                 SEI                     ; disable interrupts
  1021.  
  1022. ; *** Insert code here to enable receiver interrupts on your device
  1023.  
  1024.                 pld                     ; recover old direct page
  1025.                 plp                     ; recover old interrupt state
  1026.                 lda #0                  ; and return no-error (none possible)
  1027.                 clc
  1028.                 rtl
  1029.                 EndP
  1030.  
  1031.  
  1032. ************************************************************
  1033. *******************
  1034. *
  1035. DRVRRecvIntOff  PROC
  1036. *
  1037. * Description:  This routine will be called when the MIDI tools need to
  1038. *       Disable receiver interrupts on your device.
  1039. *
  1040. *
  1041. * Inputs:       None
  1042. *
  1043. * Outputs:      None
  1044. *
  1045. * External Refs:
  1046. *
  1047. * Entry Points:
  1048. *
  1049. ************************************************************
  1050. *******************
  1051.  
  1052.                 php                     ; save proc status/interrupt state
  1053.                 phd                     ; save the old direct page
  1054.                 tcd                     ; use the MIDI tools DPage
  1055.                 SEI                     ; disable interrupts
  1056.  
  1057. ; *** Insert code here to Disable receiver interrupts on your device
  1058.  
  1059.                 pld                     ; recover old direct page
  1060.                 plp                     ; recover old interrupt state
  1061.                 lda #0                  ; and return no-error (none possible)
  1062.                 clc
  1063.                 rtl
  1064.                 EndP
  1065.  
  1066.  
  1067. ************************************************************
  1068. *******************
  1069. *
  1070. DRVRNotImplemented      PROC
  1071. *
  1072. * Description:  Dummy routine, should leave the stack alone and return
  1073. *       no error
  1074. *
  1075. *
  1076. * Inputs:       None
  1077. *
  1078. * Outputs:      None
  1079. *
  1080. * External Refs:
  1081. *
  1082. * Entry Points:
  1083. *
  1084. ************************************************************
  1085. *******************
  1086.                 lda #0
  1087.                 clc
  1088.                 RTL
  1089.                 EndP
  1090.  
  1091.                 END
  1092.  
  1093.  
  1094. Further Reference:
  1095. o       Apple IIgs Toolbox Reference Update
  1096.  
  1097.